package com.demo.java.OD201_250.OD228;

import java.util.*;

/**
 * @author bug菌
 * @Source 公众号：猿圈奇妙屋
 * @des： 【跳格子】问题
 * @url： https://blog.csdn.net/weixin_43970743/article/details/145925158
 */
public class OdMain {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 读取格子的数量 (N)
        int N = sc.nextInt();

        // 读取依赖关系的数量 (M)
        int M = sc.nextInt();

        // 创建邻接表来跟踪格子之间的依赖关系
        List<Integer>[] dependencies = new ArrayList[N];
        for (int i = 0; i < N; i++) {
            dependencies[i] = new ArrayList<>();
        }

        // 创建一个入度数组来跟踪每个格子有多少个其他格子依赖它
        int[] indegree = new int[N];
        Arrays.fill(indegree, 0);

        // 读取依赖关系并构建依赖图
        for (int i = 0; i < M; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            dependencies[a].add(b);
            indegree[b]++;
        }

        // 使用队列执行拓扑排序
        Queue<Integer> queue = new LinkedList<>();
        // 将所有入度为0的格子加入队列
        for (int i = 0; i < N; i++) {
            if (indegree[i] == 0) {
                queue.offer(i);
            }
        }

        // 处理队列中的格子，检查是否能够按顺序打开
        int count = 0; // 能打开的格子的数量
        while (!queue.isEmpty()) {
            int current = queue.poll();
            count++;

            // 对于每个依赖于当前格子的格子，减少它的入度，如果它的入度为0，则加入队列
            for (int neighbor : dependencies[current]) {
                indegree[neighbor]--;
                if (indegree[neighbor] == 0) {
                    queue.offer(neighbor);
                }
            }
        }

        // 如果所有格子都能按顺序打开，输出 "yes"，否则输出 "no"
        if (count == N) {
            System.out.println("yes");
        } else {
            System.out.println("no");
        }

        sc.close();
    }
}
